/*
Copyright (c) 2017-2019, 武汉市嘉仪尔科技有限公司（Wuhan jiayier Technology Co.,Ltd)

Email: 707777212@qq.com
Web: www.o2mation.cn

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef UPY_H
#define UPY_H

#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>

#include "val.h"
#include "heap.h"
#include "errcode.h"

typedef val_t (*upy_native_fn)(void * e, val_t * self, int vc, val_t * v);

typedef struct upy_native_t{
    const char * name;
    void * fn;
}upy_native_t;

typedef struct upy_buffer_t{
    uint32_t type;
    uint32_t count;
    uint32_t len;
    uint8_t * buf;
    struct upy_buffer_t * super;
}upy_buffer_t;

typedef struct upy_members_t {
    uint32_t type;
    uint32_t len;
    intptr_t *keys;
    val_t    *vals;
    struct upy_members_t * super;
} upy_members_t;

typedef struct upy_scope_t {
    uint32_t type;
    uint32_t count;
    uint32_t len;
    intptr_t *keys;
    val_t    *vals;
    struct upy_scope_t * super;
    struct upy_scope_t * parent;
    upy_buffer_t * code;
} upy_scope_t;

typedef upy_scope_t upy_function_t;
typedef upy_scope_t upy_class_t;

typedef struct upy_object_t {
    uint32_t type;
    uint32_t count;
    uint32_t len;
    struct upy_object_t *super;
    struct upy_object_t * parent;
    intptr_t ext_data;
    upy_native_fn init;
    upy_native_fn dealloc;
    upy_members_t * member;
} upy_object_t;

typedef struct upy_list_t {
    uint32_t type;
    uint32_t count;
    uint32_t len;
    val_t    *vals;
    struct upy_list_t * super;
} upy_list_t;

typedef upy_buffer_t upy_string_t;

typedef struct upy_t{
    uint8_t err;
    const char * err_arg;
    const char * file_name;
    heap_t * heap;

    val_t * sp;
    val_t * sp_base;
    int stack_size;

    upy_scope_t * scope;

    intptr_t * str_table;
    int str_table_count;
    int str_table_size;

    int32_t native_cnt;
    intptr_t * native_symbals;
    upy_native_fn * native_tbl;

    int32_t module_size;
    int32_t module_cnt;
    intptr_t * module_symbals;
    intptr_t * module_tbl;
}upy_t;

int upy_init(upy_t * e, int mem_size, int module_size);
int upy_native_set(upy_t * e, upy_native_t * n);

void upy_heap_gc(upy_t *e);
int upy_heap_prepare(upy_t *e, int size);
void upy_set_err(upy_t * e, int err, const char *arg);

char *upy_string_get(upy_t * e, int id);

upy_buffer_t * upy_buffer_create(upy_t *e, int len);
int upy_buffer_len(val_t * v);
uint8_t *upy_buffer_addr(val_t * v);

upy_string_t * upy_heap_string_create(upy_t *e, int len);
int upy_string_len(val_t * v);
uint8_t *upy_string_addr(val_t * v);

upy_object_t * upy_object_create(upy_t * e, int type, int count);
upy_list_t* upy_tuple_create(upy_t * e, uint16_t count);
upy_list_t* upy_list_create(upy_t * e, uint16_t count);
int upy_list_len(val_t * v);
int upy_list_count(val_t * v);

upy_object_t * upy_object_new(upy_t * e, upy_class_t * cls);
val_t * upy_object_prop_get(upy_t *e, upy_object_t * o, const char* name);
void upy_object_prop_set(upy_t * e, upy_object_t * o, int index, const char* name, val_t v);
int upy_object_prop_set_value(upy_t * e, upy_object_t * o, const char *key, val_t v);
int upy_object_prop_append(upy_t * e, upy_object_t * o, int key, val_t * v);

upy_class_t *upy_class_create(upy_t * e, int size);
void upy_class_prop_set(upy_t * e, upy_class_t * o, int index, const char *name, val_t v);
upy_object_t * upy_module_create(upy_t * e, const char* name, int size);
upy_object_t * upy_module_add(upy_t * e, const char* name, upy_object_t * v);
upy_object_t * upy_module_get(upy_t * e, const char* name);

int upy_str_insert(upy_t *p, const char *str, int alloc);

/*** virtual machine ***/
int upy_vm_start(upy_t * e);
int upy_vm_run_callback(upy_t * e, upy_scope_t * scope, val_t *args, int argc, int stack_size);
int upy_vm_boot(upy_t *e);
int upy_vm_init(upy_t * env, int heap_size, int stack_size, int str_table_size, int module_size);
/*** end of virtual machine ***/

/*** Implementation ***/
extern const char *upy_vm_load(upy_t *e, char * file_name);
extern void * upy_malloc(int size);
extern void upy_free(void * mem);
extern void (*upy_print)(const char *fmt, ...);
/*** end of Implementation ***/
#endif
